/*
 *  \author Marcin Krzewski
 *  \author Katarzyna Rusinowska 
 *  \author Jakub Sitnicki   
 *  \date    06/2009
 */

#ifndef _COMMAND_HPP_
#define _COMMAND_HPP_

#include <boost/gil/gil_all.hpp>

#include "../ged/typedefs.hpp"
#include "Image.hpp"
#include "ImageLayer.hpp"

namespace ged {

//!Klasa czysto abstrakcyjna reprezentująca komendy
class Command {
public:
	//! Konstruktor
	Command(){}
	//! Wirtualny destruktor
	virtual ~Command(){}
	//!Wykonanie komendy
	virtual void execute(const PImage im) = 0;
	//!Cofanie komendy
	virtual void unExecute(const PImage im) = 0;

};
//! Klasa reprezentująca komende odbicia obrazu góra/dół
class FlipUpDownCommand: public Command {
public:
	//!Konstruktor
	FlipUpDownCommand();
	//!Wirtualny destruktor
	virtual ~FlipUpDownCommand();
	
	//!Wykonanie komendy
	/*
	 *\param im obrazek przechowujący wiele warstw
	*/
	virtual void execute(const PImage im);
	
	//!Cofanie komendy
	/*
	 *\param im obrazek przechowujący wiele warstw
	*/
	virtual void unExecute(const PImage im);

};
//! Klasa reprezentująca komende odbicia obrazu prawo/lewo
class FlipLeftRightCommand: public Command {
public:
	//!Konstruktor
	FlipLeftRightCommand();
	//!Wirtulany destruktor
	virtual ~FlipLeftRightCommand();
	
	//!Wykonanie komendy
	/*
	 *\param im obrazek przechowujący wiele warstw
	*/
	virtual void execute(const PImage im);

	//!Cofanie komendy
	/*
	 *\param im obrazek przechowujący wiele warstw
	*/
	virtual void unExecute(const PImage im);

};
//!Klasa reprezentująca komenende wycinania fragmentu obrazka
class SubimageCommand: public Command {
public:
	//!Konstruktor
	/*
	 *\param x_m y_m punkt rozpoczęcia wycinania
	 *\param w szerokość nowego obrazka 
	 *\param h wysokość nowego obrazka
	*/
	SubimageCommand(int x_m ,int y_m, int w, int h);
	//!Wirtualny destruktor
	virtual ~SubimageCommand();
	
	//!Wykonanie komendy
	/*
	 *\param im obrazek przechowujący wiele warstw
	*/
	virtual void execute(const PImage im);
	
	//!Cofanie komendy
	/*
	 *\param im obrazek przechowujący wiele warstw
	*/
	virtual void unExecute(const PImage im) ;
private:
	//!Współrzędne (x,y) początek wycinania obrazku 
	int x_min_;
	int y_min_;
	//!Nowa szerokość obrazka
	int width_;
	//!Nowa wysokość obrazka 
	int height_;
	//!Widok na obraz GIL skojarzony z komendą
	GILImageView img_lay_view_;
	
	
};
//!Klasa reprezentująca próbkowanie w dziedzinie przestrzeni
class SubsampleCommand: public Command{
public:
	//!Konstruktor
	/*
	 *\param x krok proobkowania wzdłóż osi x
	 *\param y krok proobkowania wzdłóż osi y
	*/
	SubsampleCommand(int x, int y);
	
	//!Wirtualny destruktor
	virtual ~SubsampleCommand();

	//!Wykonanie komendy
	/*
	 *\param im obrazek przechowujący wiele warstw
	*/
	virtual void execute(const PImage im);

	//!Cofanie komendy
	/*
	 *\param im obrazek przechowujący wiele warstw
	*/
	virtual void unExecute(const PImage im);

private:
	//! x_step_ krok proobkowania wzdłóż osi x
	int x_step_;
	//! y_step_ krok proobkowania wzdłóż osi y
	int y_step_;
	//!Widok na obraz GIL skojarzony z komendą
	GILImageView img_lay_view_;
	
};
//!Klasa reprezentująca obrót obrazka w kierunku zgodnym z ruchem wskazówek zegra 
class RotateCwCommand: public Command {
public:
	//!Konstruktor
	RotateCwCommand();
	//!Wirtulany destruktor
	virtual ~RotateCwCommand();
	
	//!Wykonanie komendy
	/*
	 *\param im obrazek przechowujący wiele warstw
	*/
	virtual void execute(const PImage im);
	
	//!Cofanie komendy
	/*
	 *\param im obrazek przechowujący wiele warstw
	*/
	virtual void unExecute(const PImage im);

};
//!Klasa reprezentująca obrót obrazka w kierunku przeciwnym do ruchu wskazówek zegra
class RotateCcwCommand: public Command {
public:
	//!Konstruktor
	RotateCcwCommand();
	//!Wirtulany destruktor
	virtual ~RotateCcwCommand();
	
	//!Wykonanie komendy
	/*
	 *\param im obrazek przechowujący wiele warstw
	*/
	virtual void execute(const PImage im);
	
	//!Cofanie komendy
	/*
	 *\param im obrazek przechowujący wiele warstw
	*/
	virtual void unExecute(const PImage im);

};
//!Klasa reprezentująca komendę wybory wyższej warstwy
class SelectLayerAboveCommand: public Command {
public:
	//!Konstruktor
	SelectLayerAboveCommand();
	//!Wirtualny destruktor
	virtual ~SelectLayerAboveCommand();
	
	//!Wykonanie komendy
	/*
	 *\param im obrazek przechowujący wiele warstw
	*/
	virtual void execute(const PImage im);
	
	//!Cofanie komendy
	/*
	 *\param im obrazek przechowujący wiele warstw
	*/
	virtual void unExecute(const PImage im);

private:
	//! chk_ sprwdzenie możliwości wykonania komendy 
	bool chk_;
};

//!Klasa reprezentująca komendę wybory niższej warstwy
class SelectLayerBelowCommand: public Command {
public:
	//!Konstruktor
	SelectLayerBelowCommand();
	//!Wirtualny destruktor
	virtual ~SelectLayerBelowCommand();

	//!Wykonanie komendy
	/*
	 *\param im obrazek przechowujący wiele warstw
	*/
	virtual void execute(const PImage im);

	//!Cofanie komendy
	/*
	 *\param im obrazek przechowujący wiele warstw
	*/
	virtual void unExecute(const PImage im);
private:
	//! chk_ sprwdzenie możliwości wykonania komendy 
	bool chk_;
};

//!Klasa reprezentująca komendę przesunięcia obrazka
class MoveLayerCommand: public Command {
public:
	//!Konstruktor
	/*
	 *\param x przesunięcie w kierunku osi x
	 *\param y przesunięcie w kierunku osi y
	*/
	MoveLayerCommand(int x,int y);
	
	//! Wirtulany destruktor
	virtual ~MoveLayerCommand();
	
	//!Wykonanie komendy
	/*
	 *\param im obrazek przechowujący wiele warstw
	*/
	virtual void execute(const PImage im);
	
	//!Cofanie komendy
	/*
	 *\param im obrazek przechowujący wiele warstw
	*/
	virtual void unExecute(const PImage im);
	
private:
	//! Przesunięcie warstwy względem obrazka
	GILPoint offset_;
	//! Margines przed wykonaniem komendy
	GILPoint oldOffset_;
	//! Przesunięcie w kierunku osi x
	int x_;
	//! Przesunięcie w kierunku osi y
	int y_;

};

}// namespace ged

#endif	// _COMMAND_HPP_
